/*
 * This file is part of OpenAstexViewer.
 *
 * OpenAstexViewer is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * OpenAstexViewer is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with OpenAstexViewer.  If not, see <http://www.gnu.org/licenses/>.
 */

//#define NOBWT

package com.openastexviewer;

/* Copyright Astex Technology Ltd. 1999 */

/*
 * 20-05-00 mjh
 *	fix bug in command line file reading that prevented maps
 *	being read unless they were the first file
 * 25-11-99 mjh
 *	change centering method to shift-click as there are problems
 *	getting double click events on linux
 * 17-11-99 mjh
 *	created
 */
import java.io.*;
import java.awt.*;
import java.util.Hashtable;
import java.util.Enumeration;
import java.util.Vector;
import java.util.Locale;
import android.view.View;
import android.widget.TextView;
import android.widget.ImageView;
import com.openastexviewer.parser.*;
import com.openastexviewer.generic.*;
import android.opengl.GLSurfaceView;
import android.content.Context;


/**
 * A component that can draw a molecule.
 */
public class MoleculeViewer /*extends GLSurfaceView implements
            MoleculeRendererListener*/ {
    /** The molecule renderer that this viewer will use. */
    public MoleculeRenderer moleculeRenderer = null;

    /** Should we show the frame rate. */
    private boolean showFrameRate = false;

    /** Should we show the version. */
    private boolean showVersion = false;

    /** Do we allow atoms to be moved. */
    private boolean moveAtomsAllowed = false;

    /** Do we exclude specified atoms from the selection. */
    private boolean excludeFromSelection = false;

    /** Are we initialised? */
    public boolean ready = true;

    /** Are we initialised? */
    public ImageView splashImage = null;

    /** Are we announcing the origin of AstexViewer. */
    public boolean announce = false;

    /** Definition of key bindings. */
    public Hashtable keyDefinitions = new Hashtable();

    /** The animation thread. */
    private Animate animationThread = null;

    /** Are we currently animating. */
    private boolean animationThreadActive = false;

    /** The animation stages. */
    private Vector stages = new Vector();

    /** Is this MoleculeViewer running in an application. */
    private boolean application = false;

    /** Are we running in application. */
    public boolean isApplication(){
        return application;
    }

    /** Set whether we are running in application. */
    public void setApplication(boolean b){
        application = b;
    }

    /** Get the animation thread. */
    public void handleAnimation(Arguments args){

 String state = args.getString("-state", "stop");
 boolean interactive = args.getBoolean("-interactive", false);

 // if state is start we just play the animation objects.
 if(state.equals("start")){
     animationThread = new Animate();
     animationThread.setMoleculeViewer(this);
     animationThread.setStages(stages);
     animationThread.setInteractive(interactive);
     animationThread.start();

     return;
 }else if(state.equals("delete")){
     stages.removeAllElements();
     return;
 }

 // otherwise we have to set up a new animationobject.
 AnimationObject stage = new AnimationObject();
 stage.setMoleculeViewer(this);

 String mode = args.getString("-mode", "rock");
 String command = args.getString("-command", null);
 int d = args.getInteger("-delay", 50);
 int steps = args.getInteger("-steps", 10);
 boolean sawInteractive = false;

 if(ViewCommand.stepMultiple != 1){
     System.out.println("step multiple is " + ViewCommand.stepMultiple);
     steps *= ViewCommand.stepMultiple;
     System.out.println("step count is now " + steps + " [was " +
          (steps/ViewCommand.stepMultiple) +"]");
 }

 stage.setSteps(steps);

 stage.setSleepDuration(d);
 stage.setCommand(command);

 if(mode.equals("rock")){
     double a = args.getDouble("-angle", 7.5);
     //double r = args.getDouble("-rate", 7.5);

     stage.setRockAngle(a);
     //stage.setRockRate(r);

     stage.setMode(AnimationObject.Rock);
 }else if(mode.equals("roll")){
     double a = args.getDouble("-angle", 360.0);
     stage.setRockAngle(a);

     stage.setMode(AnimationObject.Roll);
 }else if(mode.equals("command")){

     stage.setMode(AnimationObject.Command);

 }else if(mode.equals("recenter")){
     String matrix = args.getString("-matrix", null);

     Point3d center = null;
     double r = 10.0;
     double cf = r;
     double cb = -r;

     if(args.defined("-selection")){
  DynamicArray selection = (DynamicArray)args.get("-selection");
  center = moleculeRenderer.getCenter(selection);
  r = moleculeRenderer.getRadius(selection);
     }else if(args.defined("-center")){
  String centerString = args.getString("-center", null);

  if(centerString == null){
      Log.error("center is null: must specify \"x,y,z\"");
      return;
  }

  String tokens[] = FILE.split(centerString, ",");

  if(tokens.length != 3){
      Log.error("-center must specify \"x,y,z\"");
      return;
  }

  center = new Point3d();
  center.x = FILE.readDouble(tokens[0]);
  center.y = FILE.readDouble(tokens[1]);
  center.z = FILE.readDouble(tokens[2]);
     }else{
  Log.error("recenter must specify -selection or -center");
  return;
     }


     if(args.defined("-radius")){
  r = args.getDouble("-radius", r);
     }

     if(args.defined("-clipfront")){
  cf = args.getDouble("-clipfront", r);
     }

     if(args.defined("-clipback")){
  cb = args.getDouble("-clipback", r);
     }

     if(center == null && matrix == null){
  Log.warn("no atoms in center selection - skipping");
  return;
     }

     if(matrix != null){
  String elements[] = FILE.split(matrix, " ,");

  if(elements.length != 16){
      Log.error("matrix needs 16 components not " +
         elements.length);
      return;
  }

  Matrix rm = new Matrix();

  rm.x00 = FILE.readDouble(elements[0]);
  rm.x01 = FILE.readDouble(elements[1]);
  rm.x02 = FILE.readDouble(elements[2]);
  rm.x03 = FILE.readDouble(elements[3]);
  rm.x10 = FILE.readDouble(elements[4]);
  rm.x11 = FILE.readDouble(elements[5]);
  rm.x12 = FILE.readDouble(elements[6]);
  rm.x13 = FILE.readDouble(elements[7]);
  rm.x20 = FILE.readDouble(elements[8]);
  rm.x21 = FILE.readDouble(elements[9]);
  rm.x22 = FILE.readDouble(elements[10]);
  rm.x23 = FILE.readDouble(elements[11]);
  rm.x30 = FILE.readDouble(elements[12]);
  rm.x31 = FILE.readDouble(elements[13]);
  rm.x32 = FILE.readDouble(elements[14]);
  rm.x33 = FILE.readDouble(elements[15]);

  stage.setFinishMatrix(rm);
     }

     stage.setFinishCenter(center.x, center.y, center.z, r, cf, cb);
     stage.setMode(AnimationObject.Recenter);
 }else{
     System.out.println("handleAnimation: unhandled animation mode " + mode);
 }

 stages.addElement(stage);
    }

    /** Try and remove a thread after it has finished running. */
    public synchronized void removeAnimationThread(Thread t){

 if(animationThread != null){
     //animationThread.stop();
     animationThread = null;
     animationThreadActive = false;
 }

 dirtyRepaint();
    }

    /** Are we animating? */
    public boolean animating(){
 if(animationThread != null &&
    animationThread.isAlive() &&
    animationThread.getInteractive() == false){
     return true;
 }else{
     return false;
 }
    }

    public boolean interactiveAnimation(){
 if(animationThread != null &&
    animationThread.isAlive()){
            return animationThread.getInteractive();
        }

        return true;
    }

    /** Handle a print command in the scripting language. */
    public void handlePrint(String output){
 StringBuffer sb = new StringBuffer();
 int len = output.length();

 // process any escape characters to introduce
 // new lines etc.
 for(int i = 0; i < len; i++){
     char c = output.charAt(i);

     if(c == '\\'){
  if(i < len - 1){
      i++;
      c = output.charAt(i);
      if(c == 'n'){
   sb.append('\n');
      }else if(c == 'r'){
   sb.append('\r');
      }else if(c == '\\'){
   sb.append('\\');
      }else{
   sb.append(c);
      }
  }else{
      sb.append('\\');
  }
     }else{
  sb.append(c);
     }
 }

 System.out.println(sb.toString());
    }

    /** Handle (de)activation of animation thread. */
    public void suspendAnimationThread(boolean run){
 if(animationThreadActive){
     if(run){
  animationThread.resume();
     }else{
  animationThread.suspend();
     }
 }
    }

    /** Execute a command in the moleculeRenderer. */
    public void execute(String s){
 moleculeRenderer.execute(s);
    }

    /** Default constructor. */
    public MoleculeViewer( ){    }
    
    public void dirtyRepaint(){
    	 moleculeRenderer.dirty = true;
    	 repaint();
    }
    	 
    public void addMolecule(Molecule molecule){
    	 moleculeRenderer.addMolecule(molecule);
    }
    public MoleculeRenderer getMoleculeRenderer(){
 return moleculeRenderer;
    }
    
    /** Force the awt image to get replaced. */
    public void resetAwtImage(){
    	/*
 awtImage = null;
 moleculeRenderer.dirty = true;
 */
    }
    
    /** Add a map to the renderer. */
    public void addMap(Map map){
 moleculeRenderer.addMap(map);
    }
    
    public void repaint() {}
    
    public static void main(String args[]){
    	/*
    	 Frame frame = new Frame();
    	 frame.setLayout(new BorderLayout());

    	 MoleculeViewer moleculeViewer = new MoleculeViewer();

    	        moleculeViewer.setApplication(true);

    	 frame.addWindowListener(moleculeViewer);

    	 if(false){
    	     moleculeViewer.setUsePopupMenu(true);
    	     moleculeViewer.createMenuBar();
    	 }else{
    	     frame.setMenuBar(moleculeViewer.createMenuBar());
    	 }

    	 boolean quiet = false;
    	  
    	 // if the system property arraycopy is set to true
    	 // then the renderer should use arraycopy to clear
    	 // its buffers rather than brute force
    	 String arraycopy = System.getProperty("arraycopy");
    	 if(arraycopy != null && arraycopy.equals("true")){
    	     moleculeViewer.setArrayCopy(true);
    	 }

    	        boolean loadMolecules = true;
    	        MoleculeRenderer moleculeRenderer =
    	            moleculeViewer.getMoleculeRenderer();

    	        for(int i = 0; i < args.length; i++){
    	        
    	            //System.out.println("args " + args[i]);
    	            if(args[i].endsWith(".xml")){






    	            }else if(args[i].endsWith(".script")){
    	                moleculeViewer.executeScript(args[i]);
    	            }else if("-execute".equals(args[i]) ||
    	                     "-e".equals(args[i]) ){
    	                moleculeViewer.execute(args[++i]+";");
    	            }else if(args[i].endsWith(".tmesh") ||
    	                     args[i].endsWith(".ply") ){
    	                Tmesh tm = Tmesh.read(args[i]);
    	                moleculeRenderer.renderer.addGraphicalObject(tm);
    	            }else if("-c".equals(args[i])){
    	                if(i + 1 < args.length){
    	                    i++;
    	                    String centerString = args[i];
    	                    DynamicArray centerSelection =
    	                        moleculeRenderer.getAtomsInSelection(centerString);

    	                    moleculeRenderer.setCenter(centerSelection);
    	                }
    	            }else if("-quiet".equals(args[i]) ||
    	                     "-q".equals(args[i])){
    	                quiet = true;
    	            }else if("-maps".equals(args[i]) ||
    	                     "-map".equals(args[i]) ||
    	                     "-m".equals(args[i])){
    	                loadMolecules = false;
    	            }else{
    	                if(loadMolecules){
    	                    moleculeViewer.loadMolecule(args[i]);
    	                }else{
    	                    moleculeViewer.loadMap(args[i]);
    	                }
    	            }
    	 }

    	 if (quiet) return;

    	        if(true){
    	            Panel mvp = new Panel();
    	            mvp.setLayout(new BorderLayout());
    	            mvp.add(moleculeViewer, BorderLayout.CENTER);
    	            frame.add(mvp, BorderLayout.CENTER);
    	            
    	            Panel bottomPanel = new Panel();
    	            //bottomPanel.setLayout(new GridLayout(2,1));
    	            
    	            // center panel
    	            //Panel centerPanel = new Panel();
    	            //centerPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 2, 2));
    	            //centerPanel.add(new Label("Centre"));
    	            //moleculeViewer.centerField = new TextField(10);
    	            //moleculeViewer.centerField.addActionListener(moleculeViewer);
    	            //centerPanel.add(moleculeViewer.centerField);
    	            //moleculeViewer.moleculeRenderer.renderer.setColor(0x00ff00);
    	            //bottomPanel.add(centerPanel);
    	            
    	            // cmmand panel
    	            Panel commandPanel = new Panel();
    	            //commandPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 3, 2));
    	            //commandPanel.add(new Label("command"));
    	            moleculeViewer.commandField = new TextField(80);
    	            moleculeViewer.commandField.addActionListener(moleculeViewer);
    	            commandPanel.add(moleculeViewer.commandField);
    	            moleculeViewer.moleculeRenderer.renderer.setColor(0x00ff00);
    	            bottomPanel.add(commandPanel);

    	            frame.add(bottomPanel, BorderLayout.SOUTH);
    	        }else{
    	            frame.setLayout(new SplitterLayout(SplitterLayout.HORIZONTAL));

    	            frame.add("3", moleculeViewer);
    	            SplitterBar sb = new SplitterBar();

    	            frame.add(sb);

    	            frame.add("1", new Panel());
    	        }
    	        
    	        frame.pack();
    	        frame.show();
    	*/
    	    }

    	    /** The last mouse event. */
    	    //private MouseEvent lastMouseEvent = null;

    	    /** The mouse pressed event. */
    	    //private MouseEvent mousePressedEvent = null;

    	    /** The number of frames since we last pressed the mouse button. */
    	    private int frameCount = 0;

    	    /** The time the mouse button was pressed. */
    	    private long mousePressedTime = 0;

    	    /** The atom that we picked. */
    	    private Atom pickedAtom = null;

    	    /** Has the mouse been dragged since the button was pressed. */
    	    boolean dragged = false;

    	    /** Has the center been moved by dragging the mouse. */
    	    boolean centerMoved = false;

    	    /* Implementation of MouseListener. */

    	    /** Handle a mousePressed event. */
    	 /*   public void mousePressed(MouseEvent e){
    	 requestFocus();

    	 suspendAnimationThread(false);

    	 mousePressedEvent = e;
    	 lastMouseEvent = e;

    	 dragged = false;

    	 if(e.isPopupTrigger()){
    	     showPopupMenu(e);
    	 }else if(!e.isControlDown()){

    	     if(showFrameRate){
    	  frameCount = 0;
    	  mousePressedTime = System.currentTimeMillis();
    	     }

    	     pickedAtom =
    	  moleculeRenderer.getNearestAtom(e.getX(), e.getY());

    	     if(pickedAtom != null){
    	        //System.out.println("mouse pressed over atom");
    	     }
    	 }


    	 // feed it off to the manipulator if there is one.
    	 if(e.isAltDown()){
    	     if(manipulator != null && pickedAtom != null){
    	  manipulator.pick(e, this, pickedAtom);
    	     }
    	     return;
    	 }


    	 dirtyRepaint();
    	    }
    	  */   
}
